package com.utils.regex;

import org.apache.commons.lang3.StringUtils;

import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;

public class AuthenticityVerification {
    private static final String REGEX_CHINESE = ".*[\\u4e00-\\u9fa5].*";
    private static final String REGEX_NOT_CHINESE = ".*[^\\u4e00-\\u9fa5].*";
    private static final String REGEX_ENGLISH_CHARACTER = ".*[a-zA-Z].*";
    private static final String REGEX_PUNCTUATION_NUM_CHARACTER = ".*[\\pP\\d].*";
    private static final String REGEX_NUM = "\\d*";
    private static final String REGEX_ID_CARD_END = "[\\dXx]$";
    private static final String REGEX_JGZ = ".+(字第).{4,}";
    private static final String REGEX_WGR_YJ_JLZ = "[a-zA-Z]{3}.*";
    private static final String REGEX_ID_CARD = "^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([\\d|x|X]{1})$";


    //身份证前17位每位加权因子
    private static final int[] power = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};

    //身份证第18位校检码
    private static final String[] refNumber = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};
    //省(直辖市)码表
    private static final String[] provinceCode = {"11", "12", "13", "14", "15", "21", "22",
            "23", "31", "32", "33", "34", "35", "36", "37", "41", "42", "43",
            "44", "45", "46", "50", "51", "52", "53", "54", "61", "62", "63",
            "64", "65", "71", "81", "82", "91"};

    public static void main(String[] args) {
//        String verifyName = verifyName("name，m");
//        System.out.println(verifyName);
//        System.out.println(verifyIdCard("7302255344387x", "居民身份证"));
//        System.out.println(verifyIdCard("s字第dawgsgs", "军官证"));
//        System.out.println(verifyIdCard("as112412535ssaw", "外国人永久居留证"));
//        System.out.println(verifyIdCard("810000976575468764", "港澳居民居住证"));
        System.out.println(checkName("nda dadw"));
    }

    /**
     * <b>姓名的校验</b><br>
     * 姓名中允许所有的汉字(包含生僻字)以及·和26个英文字母<br>
     * ·不得在第一位<br>
     * ·不得连续出现<br>
     * ·不能在最后一位出现
     *
     * @param str 待校验的姓名 UTF-8
     * @return 是否为合法的中文姓名
     */
    public static String checkName(String str) {
        boolean hasEn = false;
        boolean hasCh = false;
        int charLen = 0;
        String errorInfo = "姓名中不允许含有数字或者除“·”以外的符号";
        String unicodeStr = utf8ToUnicode(str);
        String[] unicodeList = unicodeStr.split("\\\\u");
        List<String> list = new LinkedList<String>();
        for (String s : unicodeList) {
            if (!s.equals("")) {
                list.add(s);
            }
        }
        boolean isPoint = false;
        if (StringUtils.isEmpty(str)) {
            return "姓名不能为空";
        }
        if (str.trim().length() != str.length()) {
            return "姓名的首位或者末位不能有空格";
        }

        for (int i = 0; i < list.size(); i++) {
            if (i + 1 == list.size() && list.get(i).equalsIgnoreCase("00b7")) {// unicode编码 00b7代表是的·
                return "姓名末位不能为“·”";//·不能在末尾
            }
            String unicode = list.get(i).toLowerCase();
            if (i == 0 && (list.get(i).equalsIgnoreCase("00b7"))) {
                return "姓名首位不能为“·”";
            }
            if (list.get(i).equalsIgnoreCase("00b7")) {
                if (isPoint) {
                    return "姓名不能连续出现“·”";//·不能连续出现
                } else {
                    isPoint = true;
                }
            } else if (list.get(i).equalsIgnoreCase("0020")) {
                isPoint = false;
            } else if (Long.parseLong(unicode, 16) <= 90L && Long.parseLong(unicode, 16) >= 65L) {
                isPoint = false;
                hasEn = true;
            } else if (Long.parseLong(unicode, 16) <= 122L && Long.parseLong(unicode, 16) >= 97L) {
                isPoint = false;
                hasEn = true;
            } else if (Long.parseLong(unicode, 16) <= 40869L && Long.parseLong(unicode, 16) >= 19968L) {
                isPoint = false;
                hasCh = true;
            } else if (Long.parseLong(unicode, 16) <= 64041L && Long.parseLong(unicode, 16) >= 59413L) {
                isPoint = false;
                hasCh = true;
            } else if (Long.parseLong(unicode, 16) <= 19893L && Long.parseLong(unicode, 16) >= 13312L) {
                isPoint = false;
                hasCh = true;
            } else if (Long.parseLong(unicode, 16) <= 55401L && Long.parseLong(unicode, 16) >= 55360L) {
                try {
                    String unicode2 = list.get(++i).replaceAll("\\\\u", "").toLowerCase();
                    if (Long.parseLong(unicode2, 16) <= 57343L && Long.parseLong(unicode2, 16) >= 56320L) {
                        isPoint = false;
                        hasCh = true;
                    } else {
                        return errorInfo;
                    }
                } catch (Exception e) {
                    return errorInfo;
                }
            } else {
                return errorInfo;
            }
            charLen += 1;
        }
        if (hasCh && hasEn) {
            return "姓名不允许含有汉字同时又含有字母";
        }
        if ((hasCh && !hasEn && charLen > 25) || (!hasCh && hasEn && str.length() > 50)) {
            return "姓名长度不超过25个汉字或者50个字符";
        }
        if (str.length() < 2) {
            return "姓名长度不小于2个字符";
        }
        return null;
    }

    public static String utf8ToUnicode(String str) {
        str = (str == null ? "" : str);
        String tmp;
        StringBuilder sb = new StringBuilder(1000);
        char c;
        int i, j;
        sb.setLength(0);
        for (i = 0; i < str.length(); i++) {
            c = str.charAt(i);
            sb.append("\\u");
            j = (c >>> 8); // 取出高8位
            tmp = Integer.toHexString(j);
            if (tmp.length() == 1)
                sb.append("0");
            sb.append(tmp);
            j = (c & 0xFF); // 取出低8位
            tmp = Integer.toHexString(j);
            if (tmp.length() == 1)
                sb.append("0");
            sb.append(tmp);
        }
        return sb.toString();
    }

//    public static String utf8ToUnicode(String inStr) {
//        char[] myBuffer = inStr.toCharArray();
//
//        StringBuilder sb = new StringBuilder();
//        for (int i = 0; i < inStr.length(); i++) {
//            Character.UnicodeBlock ub = Character.UnicodeBlock.of(myBuffer[i]);
//            if (ub == Character.UnicodeBlock.BASIC_LATIN) {
//                //英文及数字等
//                sb.append(myBuffer[i]);
//            } else if (ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {
//                //全角半角字符
//                int j = (int) myBuffer[i] - 65248;
//                sb.append((char) j);
//            } else {
//                //汉字
//                short s = (short) myBuffer[i];
//                String hexS = Integer.toHexString(s);
//                String unicode = "\\u" + hexS;
//                sb.append(unicode.toLowerCase());
//            }
//        }
//        return sb.toString();
//    }

    public static String verifyName(String name) {
        if (StringUtils.isAllBlank(name)) {
            return "姓名不能为空";
        }
        if (name.length() < 2) {
            return "姓名长度不小于2个字符";
        }
        if (Pattern.matches(REGEX_CHINESE, name)) {
            if (Pattern.matches(REGEX_ENGLISH_CHARACTER, name)) {
                return "姓名字段中不允许含有汉字又同时含有字母";
            }
            if (Pattern.matches(REGEX_NOT_CHINESE, name.replace("·", ""))) {
                return "姓名为汉字的，间隔符只允许使用“·”";
            }
            if (name.length() > 25) {
                return "姓名不允许长度超过25个汉字";
            }
        } else {
            if (name.getBytes(StandardCharsets.UTF_8).length > 120) {
                return "姓名字节数在120以内";
            }
            if (Pattern.matches(REGEX_PUNCTUATION_NUM_CHARACTER, name.replace("，", "").replace(" ", ""))) {
                return "姓名为非中文则分隔符必须使用“，”(半角）";
            }
        }
        return null;
    }

    public static String verifyIdType(String idType) {
        return "非空值，且必须在枚举值范围内，详见枚举值控制参数表";
    }

    public static String verifyIdCard(String idCard, String idType) {
        if (StringUtils.isAllBlank(idCard)) {
            return "证件号码不能为空";
        }
        if ("居民身份证".equals(idType)) {
            if (idCard.length() != 18) {
                return "居民身份证长度为18位";
            }
            //长度为18位，不能以7、8、9开头，且全部为数字
            if (!Arrays.asList('7', '8', '9').contains(idCard.charAt(0))) {
                if (!Pattern.matches(REGEX_NUM, idCard)) {
                    return "居民身份证格式错误";
                }
                //长度为18位，前面17位须是数字，最后一位可以为大小写的字母X/x
            } else if (Pattern.matches(REGEX_NUM, idCard.substring(0, 17))) {
                if (!idCard.substring(17).matches(REGEX_ID_CARD_END)) {
                    return "居民身份证格式错误";
                }
            }
            if (!checkIdNoLastNum(idCard)) {
                return "居民身份证格式有误";
            }
            return null;
        } else if (Arrays.asList("港澳居民通行证", "护照", "台湾居民通行证").contains(idType)) {
            if (verifyIdCard(idCard, "居民身份证") == null) {
                return "证件号码有误";
            }
            if (idCard.length() < 7) {
                return "证件号码长度有误";
            }
            return null;
        } else if ("内部证件".equals(idType)) {
            if (verifyIdCard(idCard, "居民身份证") == null) {
                return "内部证件有误";
            }
            if (!Arrays.asList('7', '8', '9').contains(idCard.charAt(0))) {
                return "内部证件格式有误";
            }
            if (Pattern.matches(REGEX_NUM, idCard)) {
                return null;
            }
            return "内部证件格式有误";
        } else if ("军官证".equals(idType)) {
            if (idCard.length() > 30) {
                return "军官证格式有误";
            }
            if (!Pattern.matches(REGEX_JGZ, idCard)) {
                return "军官证格式有误";
            }
            return null;
        } else if ("外国人永久居留证".equals(idType)) {
            if (idCard.length() != 15) {
                return "外国人永久居留证长度有误";
            }
            if (!Pattern.matches(REGEX_WGR_YJ_JLZ, idCard)) {
                return "外国人永久居留证格式有误";
            }
            return null;
        } else if (Arrays.asList("港澳居民居住证", "台湾居民居住证").contains(idType)) {
            if (idCard.length() != 18) {
                return "居住证长度有误";
            }
            if (!Arrays.asList("810000", "820000", "830000").contains(idCard.substring(0, 6))) {
                return "居住证格式错误";
            }

            //长度为18位，不能以7、9开头，且全部为数字
            if (!Arrays.asList('7', '9').contains(idCard.charAt(0))) {
                if (!Pattern.matches(REGEX_NUM, idCard)) {
                    return "居住证格式错误";
                }
                //长度为18位，前面17位须是数字，最后一位可以为大小写的字母X/x
            } else if (Pattern.matches(REGEX_NUM, idCard.substring(0, 17))) {
                if (!idCard.substring(17).matches(REGEX_ID_CARD_END)) {
                    return "居住证格式错误";
                }
            }
            if (!checkIdNoLastNum(idCard)) {
                return "居住证格式错误";
            }
            return null;
        }
        return null;
    }

    /**
     * 二代身份证号码有效性校验
     *
     * @param idNo 二代身份证号码
     * @return
     */
    public static boolean isValidIdNo(String idNo) {
        return isIdNoPattern(idNo) && isValidProvinceId(idNo.substring(0, 2))
                && isValidDate(idNo.substring(6, 14)) && checkIdNoLastNum(idNo);
    }

    /**
     * 二代身份证正则表达式
     *
     * @param idNo 二代身份证号码
     * @return
     */
    private static boolean isIdNoPattern(String idNo) {
        return Pattern.matches(REGEX_ID_CARD, idNo);
    }

    /**
     * 检查身份证的省份信息是否正确
     *
     * @param provinceId 身份证前2位
     * @return
     */
    public static boolean isValidProvinceId(String provinceId) {
        for (String id : provinceCode) {
            if (id.equals(provinceId)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断日期是否有效
     *
     * @param inDate yyyyMMdd
     * @return
     */
    public static boolean isValidDate(String inDate) {
        if (inDate == null) {
            return false;
        }
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        if (inDate.trim().length() != dateFormat.toPattern().length()) {
            return false;
        }
        dateFormat.setLenient(false);//执行严格的日期匹配
        try {
            dateFormat.parse(inDate.trim());
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 计算身份证的第十八位校验码
     */
    public static String sumPower(int[] cardIdArray) {
        int result = 0;
        for (int i = 0; i < power.length; i++) {
            result += power[i] * cardIdArray[i];
        }
        return refNumber[(result % 11)];
    }

    /**
     * 校验身份证第18位是否正确
     */
    public static boolean checkIdNoLastNum(String idNo) {
        if (idNo.length() != 18) {
            return false;
        }
        char[] tmp = idNo.toCharArray();
        int[] cardIdArray = new int[tmp.length - 1];
        for (int i = 0; i < tmp.length - 1; i++) {
            cardIdArray[i] = Integer.parseInt(tmp[i] + "");
        }
        String checkCode = sumPower(cardIdArray);
        String lastNum = tmp[tmp.length - 1] + "";
        return checkCode.equalsIgnoreCase(lastNum);
    }
}

